package com.lawliet.example.filter;

import com.alibaba.fastjson.JSON;
import com.lawliet.example.model.system.SysUser;
import com.lawliet.example.model.vo.Result;
import com.lawliet.example.model.vo.UserDetailsImpl;
import com.lawliet.example.repository.system.SysUserMapper;
import com.lawliet.example.service.impl.CustomUserDetailsService;
import com.lawliet.example.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
 
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${permit-url}")
    private  String WHITE_LIST;

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${expire_time}")
    private  Integer expireTime;

    @Override
    protected void doFilterInternal(HttpServletRequest request,  HttpServletResponse response,  FilterChain filterChain) throws ServletException, IOException {
        String requestPath = request.getRequestURI();

        // 如果是白名单接口，直接放行，不验证 token
        if (isInWhiteList(requestPath)) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = request.getHeader("Authorization");

        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }
 
        token = token.substring(7);

        /*根据jwtToken 取出用户名*/
        String userName = redisTemplate.opsForValue().get(token);

        if (Strings.isEmpty(userName)) {
            writeError(response,HttpServletResponse.SC_UNAUTHORIZED,"登录信息已过期");
        }else {
            UserDetails userDetails = customUserDetailsService.loadUserByUsername(userName);

            /*每一次请求都刷新token过期时间*/
            redisTemplate.expire(token, expireTime, TimeUnit.MINUTES);

            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

            // 如果是有效的jwt，那么设置该用户为认证后的用户
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

            filterChain.doFilter(request, response);
        }
    }

    /**
     * 异常格式封装
     * @param response
     * @param status
     * @param message
     * @throws IOException
     */
    private void writeError(HttpServletResponse response, int status, String message) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(status);
        response.getWriter().write(JSON.toJSONString(Result.error(status, message)));
    }

    /**
     * 白名单路径
     * @param path
     * @return
     */
    private boolean isInWhiteList(String path) {
        return Arrays.asList(WHITE_LIST.split(",")).stream().anyMatch(path::contains);
    }
}